基于VITS的galgame角色语音合成+使用Kaggle的训练教程(9nine版) 您所在的位置:网站首页 kaggle 输出文件 基于VITS的galgame角色语音合成+使用Kaggle的训练教程(9nine版)

基于VITS的galgame角色语音合成+使用Kaggle的训练教程(9nine版)

#基于VITS的galgame角色语音合成+使用Kaggle的训练教程(9nine版)| 来源: 网络整理| 查看: 265

(注:本专栏只讨论相关技术,不涉及任何其他目的,如侵删)

摘要

从2022年7月开始,利用语音合成模型进行动漫角色的语音合成在B站掀起了一股小范围热潮。一开始人们使用tacotron2模型进行语音合成,随后,效果更好的VITS模型逐渐受到人们的关注,并最终成为动漫角色语音合成的主流模型。VITS模型由韩国科学技术院(KAIST)的研究者们于2021年提出,其通过结合变分推理、标准化流和对抗训练,实现更自然、更多样的语音合成。截至目前,B站上已出现不少利用Colab在线训练VITS模型的教程视频,然而,免费版Colab每天只提供几小时的GPU(Tesla T4)使用时间,且需要定时操作以防止下线。Kaggle平台每周提供了30h的GPU(1块Tesla P100或者2块Tesla T4)使用时间,同时支持后台训练。B站上缺乏相关的Kaggle详细教程,因此,本专栏以9nine系列游戏为例,介绍了如何使用Kaggle训练自己的VITS模型,同时包含9nine系列游戏的解包内容。

前言(废话)

本专栏是对上一期视频的补充:

这期视频大概断断续续做了差不多一个月,一开始提取数据集、学习模型、debug代码加上训练花了一个多星期,中间一个星期在忙毕业论文,结果再次打开发现原来的代码运行的时候会报错。我研究了两三天,最后发现问题出在torch的版本上,于是我又重新改写了里面的函数,重新debug,昨天终于把这个视频发出来了,确实不容易。

上期视频本质上还是在前人的工作上修修补补,技术含量较低,由于本人还是初学者,代码部分难免有许多不正确之处,欢迎大家指正。

Kaggle Notebook:https://www.kaggle.com/code/littleweakweak/train-vits-ss

预训练VITS模型链接:https://huggingface.co/spaces/skytnt/moe-tts

VITS模型的基本介绍

VITS模型本身比较复杂,对其结构感兴趣的B友可以看下面这个视频或者这个链接(https://zhuanlan.zhihu.com/p/419883319),讲的很细(虽然我自己也没看完)。

VITS是一个端到端的语音合成模型,最终的效果是给定一段文本输入,可以直接输出对应的语音波形。项目链接如下:

VITS项目链接:https://github.com/jaywalnut310/vits

用于日语语音合成的VITS项目链接:https://github.com/CjangCjengh/vits

Galgame解包和数据集提取

这里我们使用KrKrExtract对9nine游戏进行解包。解包过程可以参考我的第一期专栏:

9nine系列游戏有四部,每部的文本文件以a-d开头,同时每部游戏里的音频文件命名编号都是独立的(即九九九里有名为sr0001.wav的音频,天天天里也有名为sr0001.wav的音频,后两部同理)。

九九九提取出来的脚本文件

为后续训练方便,我把所有的scn文件放在一个文件夹里,然后用Freemote转换成json格式。

然后从每部游戏的音频文件夹中,找到对应角色的音频,这里我选择的是新海天,因此找的是sr开头的文件。(注:sr开头的文件不只在sr文件夹下,在ep1-ep3文件夹中也有,因此需要注意一下不要提取漏了。)

把每部游戏的ogg音频文件分别放在四个文件夹中:

随后我们需要把ogg文件转换成wav格式,同时设置采样率为22050。最终,所有wav文件被放在一个文件夹中,重命名为sr0001a.wav、sr0001b.wav、sr0001c.wav,后续以此类推。

为此,我写了两个py脚本,分别用于生成文本文件和音频格式转换。

生成文本文件:

运行代码前同样需要指定vits模型所在文件夹,以及scn文件的存储文件夹。这段代码和第一期专栏中的有一些不同,主要是因为9nine里存在两个角色同时说一句话的情况,因此需要再加一个判断,提取出选定的角色。其他细节可以参考第一期专栏。

处理音频文件:

处理音频文件使用了pydub库,运行前需要指定原始ogg文件和转换后的wav文件的存储路径。如果音频文件较多,转换过程会有些慢,可以考虑os.rename统一重命名后用格式工厂转换。

在最后我加了一个验证环节,即看看filelists中的记下的音频数和我们最终转换后的音频数是否一致,如果一致则说明提取成功,否则可能是你的音频文件提取漏了。

最终的txt文件和wav文件夹长下面这样:

txt文件wav文件夹模型使用KagglleKaggle数据集上传

数据集提取完成后,我们需要上传到Kaggle的Dataset上。我们将wav文件夹和filelists文件夹压缩,然后上传到Kaggle上,这里可以参考上一期视频(左上角Create - New Dataset):

进入Kaggle

下一步进入Notebook,添加数据集(“Add Data”),设置Accelerator为GPU。然后划到页面最下方的代码块,填入音频文件、数据集和测试集的路径。上述步骤可以依照视频中的操作进行。

(我原来想用2块T4进行多卡训练的,但是jupyter notebook应该不支持直接调用torch.multiprocessing.run,想多卡训练的可以考虑写一个py脚本,然后用命令行模式运行)

下面说一下我代码里相比原项目修改的部分,不感兴趣的可以直接跳到下一部分。

如果现在Kaggle新建一个Notebook,里面默认的torch版本是2.0.0:

原项目中TextAudioLoader为Dataset的子类,在__getitem__函数中调用了get_audio_text_pair()函数,进而调用get_audio()函数。get_audio()函数调用了spectrogram_torch()函数对输入波形做短时Fourier变换(STFT),返回相应的频谱。

而在spectrogram_torch()函数中,调用了torch.stft()函数进行STFT:

查阅官方文档,torch.stft()的最后一个参数是return_complex:

return_complex表示stft的返回值是否是复数形式。return_complex=True,返回tensor的数值类型为复数;return_complex=False,分别返回复数的实部和虚部(相当于最后多了一个长度为2的维度)。在torch前几个版本中,torch.stft()不要求指定return_complex,此时默认返回的形式为实部和虚部。比如input的shape是(3, 5, 10),返回的tensor维度应该是(3, 5, 10, 2)。按照原项目的代码,最后返回的实际上是每个复数的模(即对最后一个维度平方后求和):

而到了2.0版本之后,torch强制要求stft函数中return_complex=True,此时返回的tensor维度和之前的对不上,因此需要调用view_as_real()函数把复数恢复成实部和虚部的形式:

所以解决这个问题可以降低torch的版本,这个我试了一下好像没成功,所以我只能在Notebook里修改spectrogram_torch()函数。

另外,模型生成器的forward()里调用了rand_slice_segments()函数进行随机切片:

注意这里的x和y分别是文本和频谱,z是文本序列经过编码之后的embedding(这个命名方式蒸乌鱼):

rand_slice_segments()函数做的事情是:在batch中的每一个样本中,随机截取一定长度的文本序列对应的embeddings,上面的y_length对应padding之后的输入序列的有效长度。segment_size参数表示截取片段的长度,在模型定义时传入的参数是hps.train.segment_size // hps.data.hop_length = 8196/256 = 32:

所以这一步截取实际上得到的是embeddings的切片序列,每个序列长度为32。

而在训练过程中,我们需要把前面的切片序列对应的频谱片段也找出来,因此需要传入ids_slice:

所以频谱片段的长度应该大于切片序列的长度,因此我在定义数据集时加了一步筛选,去掉频谱长度小于32的样本:

以上就是我主要修改的代码部分,接下来是模型训练。

(上面的代码部分的分析可能不完善,欢迎大佬指正)

模型训练

训练前我们需要指定epochs和batch size,batch size可以先调大一些,跑完一个epoch看看占用率,如果GPU没有爆显存那就没问题。第一次训练时把first_train=True,这样会下载原up的预训练模型。然后设置学习率,下一步就可以run all了。

恢复训练时上传checkpoint文件到数据集,设置first_train=False,其他同视频一样。

调试完成后,可以用save version进行后台训练。save version只有在全部运行完或者终止运行的时候才可以看输出,如果输出文件夹没有文件就多刷新几次。

Kaggle的其他具体操作可以看我的第一期专栏,本地推理部分可以看我的第三期专栏。

结语

1. 我在第一期专栏中提到tacotron2输出随机性的问题,当时不了解TTS模型,后面看网上的教程才知道,这是为了让同一句话有不同的读法和感情,因此VITS也是如此。可以多输出几次进行比较,选出发音和情感最好的一版。

2. 我个人的推理经验:模型在读长句子的时候可能情感比较低沉,这时候可以在句尾加日文感叹号,同时如果模型最后一个字发音不完全,可以再加个句号(经验,不确定是否严谨);而在读比较短的句子的时候,最好不要加感叹号,否则读出来的效果可能会过于激动。反正可以多试试,找到最合适的版本。

3. 这又是拿VITS水了一期,VITS相比tacotron2还是复杂了许多,同时也遇到了很多之前没想到的麻烦。不管怎么说,还是学到了不少,欢迎大家一起交流讨论。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有